今天要介紹的是 Intepreter,它是一種 Behavior Pattern。這個 Pattern 的目的是要用來解釋已經被定義的文法,將一段敘述轉換成表示法。那麼我們就來了解一下這個特別的 Design Pattern 吧!
當一個特定的問題發生的頻率夠高,那麼就應該值得定義一個簡單語言來表示它,而當定義了這樣的語言後,就可以使用 Interpreter Pattern 來解決轉譯句子的問題。
舉例來說:搜尋特定符合特定模式的字串,這是一個很通用常見的問題,而 Regular Expression 就是一個用來指定字串模式的標準的語言。而要怎麼將一個這樣的語言轉換成程式語言可使用的表示,就可以透過套用 Interpreter Pattern,將文字敘述轉換成抽象語法樹(Abstract Syntax Tree),就可為程式語言使用。
AbstractExpression
:定義一個在抽象語法樹(Abstract Syntax Tree)中所有節點都有共同的抽象化Interpret操作。TerminalExpression
:
NonterminalExpression
:文法中的每一個規則都代表了一個非終結表達式。Context
:包含 Interpreter 以外的全域訊息。Client
:
TerminalExpression
和 NonterminalExpression
的實體。interpret
操作者。當有一個語言需要被解譯的時候可以使用 Interpreter Pattern,而且你可以用抽象語法樹(Abstract Syntax Tree)來表示一個語言的聲明。Interpreter Pattern 特別適合於:
我們就使用簡單的加法表示式來做練習,而範例將用 Swift 來撰寫!不過因為 Swift 裡面並沒有 Abstract Class 的概念,我們可以用 Protocol 來實現 Interpreter。
class IntegerContext {
private var data = [Character: Int]()
func lookup(name: Character) -> Int {
return data[name]!
}
func assign(expression: IntegerVariableExpression, value: Int) {
data[expression.name] = value
}
}
protocol IntegerExpression {
func evaluate(_ context: IntegerContext) -> Int
func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression
func copied() -> IntegerExpression
}
class IntegerVariableExpression: IntegerExpression {
let name: Character
init(name: Character) {
self.name = name
}
func evaluate(_ context: IntegerContext) -> Int {
return context.lookup(name: self.name)
}
func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression {
if name == self.name {
return integerExpression.copied()
} else {
return IntegerVariableExpression(name: self.name)
}
}
func copied() -> IntegerExpression {
return IntegerVariableExpression(name: self.name)
}
}
class PlusExpression: IntegerExpression {
private var operand1: IntegerExpression
private var operand2: IntegerExpression
init(op1: IntegerExpression, op2: IntegerExpression) {
self.operand1 = op1
self.operand2 = op2
}
func evaluate(_ context: IntegerContext) -> Int {
return self.operand1.evaluate(context) + self.operand2.evaluate(context)
}
func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression {
return PlusExpression(op1: operand1.replace(character: character, integerExpression: integerExpression),
op2: operand2.replace(character: character, integerExpression: integerExpression))
}
func copied() -> IntegerExpression {
return PlusExpression(op1: self.operand1, op2: self.operand2)
}
}
let context = IntegerContext()
let a = IntegerVariableExpression(name: "a")
let b = IntegerVariableExpression(name: "b")
let c = IntegerVariableExpression(name: "c")
let expression = PlusExpression(op1: a, op2: PlusExpression(op1: b, op2: c))
context.assign(expression: a, value: 4)
context.assign(expression: b, value: 1)
context.assign(expression: c, value: 2)
print(expression.evaluate(context))
let newExpression = expression.replace(character: "c", integerExpression: a)
print(newExpression.evaluate(context))
Output
7
9
作者:Charles